//
//  LocationManager.m
//  CarLife
//
//  Created by yu on 2018/3/13.
//  Copyright © 2018年 jpas. All rights reserved.
//

#import "LocationManager.h"
#import "MBProgressHUD.h"
#import "ErrorInfoUtility.h"

@implementation LocationManager

+ (LocationManager *)shareLocationManager {
    static LocationManager *_shareLocationManager = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        _shareLocationManager = [[super allocWithZone:NULL] init];
    });
    return _shareLocationManager;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [LocationManager shareLocationManager];
}

- (id)copyWithZone:(NSZone *)zone
{
    return [LocationManager shareLocationManager];
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return [LocationManager shareLocationManager];
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self getLocation];
    }
    return self;
}

- (void)getLocation
{
    self.locationManager = [[AMapLocationManager alloc] init];
    self.locationManager.delegate = self;
    // 默认期望定位精度
    [self.locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
    [self.locationManager setDistanceFilter:200];
    // 默认不允许系统暂停定位
    [self.locationManager setPausesLocationUpdatesAutomatically:NO];
    // 默认不允许在后台定位
    [self.locationManager setAllowsBackgroundLocationUpdates:NO];
    [self.locationManager setLocationTimeout:15];
    [self.locationManager setLocatingWithReGeocode:YES];
}

//+ (void)setDesiredAccuracy:(CLLocationAccuracy)desiredAccuracy {
//    [[LocationManager shareLocationManager].locationManager setDesiredAccuracy:desiredAccuracy];
//}

+ (void)startUpdatingLocation {
    [[LocationManager shareLocationManager].locationManager startUpdatingLocation];
}

+ (void)stopUpdatingLocation {
    [[LocationManager shareLocationManager].locationManager stopUpdatingLocation];
}

+ (BOOL)isLocationEnabled
{
    return ([CLLocationManager locationServicesEnabled] && [CLLocationManager authorizationStatus] != kCLAuthorizationStatusDenied);
}

+ (void)getChangedAuthStatus:(ChangedAuthStatusBlock)changedAuthStatusBlock
{
    [[LocationManager shareLocationManager] getChangedAuthStatus:changedAuthStatusBlock];
}
- (void)getChangedAuthStatus:(ChangedAuthStatusBlock)changedAuthStatusBlock
{
    self.changedAuthStatusBlock = changedAuthStatusBlock;
}


+ (void)getLocationInfo:(LocationInfoBlock)locationInfoBlock
{
    [[LocationManager shareLocationManager] getLocationInfo:locationInfoBlock];
}
- (void)getLocationInfo:(LocationInfoBlock)locationInfoBlock
{
    if (![LocationManager isLocationEnabled]) return;
    self.locationInfoBlock = locationInfoBlock;
    [self.locationManager startUpdatingLocation];
}

#pragma mark - AMapLocationManagerDelegate -
- (void)amapLocationManager:(AMapLocationManager *)manager didFailWithError:(NSError *)error
{
    if ([LocationManager isLocationEnabled]) {
        [LocationManager startUpdatingLocation];
    }
}

- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode
{
    if (!location || !reGeocode) return;
    
    if (location.horizontalAccuracy < 0) return;
    
    double lat = location.coordinate.latitude;
    double lng = location.coordinate.longitude;
    
    if (self.locationInfoBlock) {
        self.locationInfoBlock(lat,lng,reGeocode);
    }
}

- (void)amapLocationManager:(AMapLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    if (self.changedAuthStatusBlock) {
        self.changedAuthStatusBlock(status);
    }
}

@end







@implementation RegeocodeRequest

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.search = [[AMapSearchAPI alloc] init];
        self.search.delegate = self;
    }
    return self;
}

- (void)start {
    AMapReGeocodeSearchRequest *regeo = [[AMapReGeocodeSearchRequest alloc] init];
    AMapGeoPoint *point = [AMapGeoPoint locationWithLatitude:self.coordinate.latitude longitude:self.coordinate.longitude];
    regeo.location = point;
    regeo.requireExtension = YES;
    regeo.radius = 800;
    [self.search AMapReGoecodeSearch:regeo];
}

#pragma mark - AMapSearchDelegate -
- (void)AMapSearchRequest:(id)request didFailWithError:(NSError *)error
{
    [self completeCallback];
    PPLog(@"AMapSearchRequest Error: %@ - %@", error, [ErrorInfoUtility errorDescriptionWithCode:error.code]);
    //    [MBProgressHUD showToast:[ErrorInfoUtility errorDescriptionWithCode:error.code]];
    if (self.reGeocodeFailBlock) {
        self.reGeocodeFailBlock([ErrorInfoUtility errorDescriptionWithCode:error.code]);
    }
}

/* 逆地理编码回调. */
- (void)onReGeocodeSearchDone:(AMapReGeocodeSearchRequest *)request response:(AMapReGeocodeSearchResponse *)response
{
    [self completeCallback];
    
    if (response.regeocode != nil) {
        if (self.reGeocodeBlock) {
            self.reGeocodeBlock(response.regeocode);
        }
    }
}

- (void)completeCallback {
    if (self.delegate && [self.delegate respondsToSelector:@selector(regeocodeRequestComplete:)]) {
        [self.delegate regeocodeRequestComplete:self];
    }
}

@end


@implementation ReGeocodeManager

+ (ReGeocodeManager *)shareReGeocodeManager {
    static ReGeocodeManager *_shareReGeocodeManager = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        _shareReGeocodeManager = [[super allocWithZone:NULL] init];
    });
    return _shareReGeocodeManager;
}

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [ReGeocodeManager shareReGeocodeManager];
}

- (id)copyWithZone:(NSZone *)zone
{
    return [ReGeocodeManager shareReGeocodeManager];
}

- (id)mutableCopyWithZone:(NSZone *)zone
{
    return [ReGeocodeManager shareReGeocodeManager];
}


- (instancetype)init
{
    self = [super init];
    if (self) {
        _regeocodeRequests = [NSMutableArray array];
    }
    return self;
}

+ (void)searchReGeocodeWithCoordinate:(CLLocationCoordinate2D)coordinate reGeocodeBlock:(ReGeocodeBlock)reGeocodeBlock reGeocodeFailBlock:(ReGeocodeFailBlock)reGeocodeFailBlock
{
    ReGeocodeManager *manager = [ReGeocodeManager shareReGeocodeManager];
    
    RegeocodeRequest *request = [[RegeocodeRequest alloc] init];
    request.delegate = manager;
    request.coordinate = coordinate;
    request.reGeocodeFailBlock = reGeocodeFailBlock;
    request.reGeocodeBlock = reGeocodeBlock;
    
    [manager.regeocodeRequests addObject:request];
    
    [request start];
}

- (void)regeocodeRequestComplete:(RegeocodeRequest *)request{
    [self.regeocodeRequests removeObject:request];
}


@end
